#pragma once

#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <functional>
#include <memory>
#include <boost/noncopyable.hpp>

#include "../http_stream.h"

//////////////////////////////////////////////////////////////////////////
//

using boost::asio::ip::tcp;

class http_stream_impl : boost::noncopyable
{
public:
	friend class http_stream;

	typedef http_stream::Progress Progress;

	http_stream_impl(std::ostream& err_stream, const std::string& server, const std::string& port = "http", size_t trans_bytes_per_once = 1024);
	virtual ~http_stream_impl();
	
	void						resolve();
	std::istream				responsed_header();
	std::istream				responsed_contents();	
	void						set_write_progress( Progress proc );
	
	template< typename Data >
	std::ostream& operator<<( const Data& data );

private:	
	void						handle_resolve(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator);
	void						handle_connect(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator);
	void						handle_write_request(const boost::system::error_code& err, size_t bytes_transferred);
	void						handle_read_status_line(const boost::system::error_code& err);
	void						handle_read_headers(const boost::system::error_code& err);
	void						handle_read_content(const boost::system::error_code& err);

	boost::asio::io_service		io_service_;
	std::string					server_;
	std::string					port_;
	std::ostream&				err_stream_;
	tcp::resolver				resolver_;
	tcp::socket					socket_;
	boost::asio::streambuf		request_;
	boost::asio::streambuf		response_;
	boost::asio::streambuf		responsed_header_;
	boost::asio::streambuf		responsed_contents_;
	std::ostream				request_stream_;
	Progress					write_progress;

	size_t						max_request_size_;
	size_t						total_translated_bytes_;
	size_t						trans_bytes_per_once_;
};

//////////////////////////////////////////////////////////////////////////
//

template< typename Data >
std::ostream& http_stream_impl::operator<<( const Data& data )
{
	return request_stream_ << data;
}

//////////////////////////////////////////////////////////////////////////